package studio.raptor.ddal.core.engine.plan.node.impl.index;

import java.util.*;
import java.util.Map.Entry;
import studio.raptor.ddal.common.exception.GenericException;
import studio.raptor.ddal.common.exception.code.RouteErrCodes;
import studio.raptor.ddal.config.model.shard.Index;
import studio.raptor.ddal.config.model.shard.Table;
import studio.raptor.ddal.core.constants.EngineConstants;
import studio.raptor.ddal.core.engine.IndexTableOps;
import studio.raptor.ddal.core.engine.ProcessContext;
import studio.raptor.ddal.core.engine.plan.node.ProcessNode;
import studio.raptor.ddal.core.parser.builder.SqlBuilder;
import studio.raptor.ddal.core.parser.result.ParseResult;

/**
 * 构造Select语句Index执行SQL
 *
 * @author Charley
 * @since 1.0
 */
public class BuildSelectIndexSql extends ProcessNode{

  @Override
  protected void execute(ProcessContext context) {
    Map<String, Index> indexTables = getIndexTable(context);
    IndexTableOps indexTableOps = assembleIndexOps(context.getStatementContext().getSqlBuilder(), context.getStatementContext().getSqlParameters(), indexTables,context);
    if(indexTableOps!=null){
      context.getStatementContext().getIndexTableOpsList().add(indexTableOps);
    }
    context.getStatementContext().setIndexTables( indexTables );
  }

  /**
   * 获取需要处理的索引信息
   *
   * @param context
   * @return
   */
  private Map<String, Index> getIndexTable(ProcessContext context){
    Map<String, Index> indexTables = new HashMap<>();
    ParseResult parseResult = context.getStatementContext().getParseResult();
    for(Table shardTable : context.getStatementContext().getShardTables()){
      if(shardTable.hasIndex()){
        int indexCount = 0;
        Index index = null;
        for(String indexColumn : shardTable.getIndexColumn().keySet()){
          if(parseResult.containsColumn(shardTable.getName(), indexColumn)){
            index = shardTable.getIndexColumn().get(indexColumn);
            indexCount++;
          }
        }
        if (indexCount > 1) {
          throw new UnsupportedOperationException(
                  "Could not deal with more than one table contain index.");
        }
        if(indexCount == 1){
          indexTables.put(shardTable.getName(), index);
        }
      }
    }
    return indexTables;
  }

  private IndexTableOps assembleIndexOps(SqlBuilder sqlBuilder, List<Object> parameters,  Map<String, Index> indexTables,ProcessContext context){
    Map.Entry<String, Index> entry = null;
    Iterator<Entry<String, Index>> iterator = indexTables.entrySet().iterator();
    boolean isCopy=true;
    Index index=null;
    //只取第一个索引表配置？
    while(iterator.hasNext()){
      entry = iterator.next();
      index=entry.getValue();
      isCopy=index.isCopy();
    }
    if (isCopy){
      return assembleIndexOpsOfCopy(sqlBuilder,parameters,entry);
    }
    else{
      return assembleIndexOpsOfIdx(sqlBuilder,parameters,entry,context,index);
    }
  }

  /**
   * 索引-副本模式
   * @param sqlBuilder
   * @param parameters
   * @param entry
   * @return
   */
  private IndexTableOps assembleIndexOpsOfCopy(SqlBuilder sqlBuilder, List<Object> parameters, Map.Entry<String, Index> entry){
    sqlBuilder.rewriteTable(entry.getKey());
//    String sql = sqlBuilder.toString();
    String sql = sqlBuilder.toStringForIndexTable();
    sql = sql.replaceAll(String.format(
            EngineConstants.REWRITE_PH_TBL_TEMPLATE,
            EngineConstants.REWRITE_PH_TBL_PREFIX, entry.getKey(), EngineConstants.REWRITE_PH_TBL_SUFFIX),
            entry.getValue().getName());
    IndexTableOps ops = new IndexTableOps();
    ops.getParameters().addAll(parameters);
    ops.setIdxSql(sql);
    return ops;
  }

  /**
   * 索引-索引模式
   * @param sqlBuilder
   * @param parameters
   * @param entry
   * @param context
   * @param index
   * @return
   */
  private IndexTableOps assembleIndexOpsOfIdx(SqlBuilder sqlBuilder, List<Object> parameters, Map.Entry<String, Index> entry,ProcessContext context,Index index){
//    sqlBuilder.rewriteTable(entry.getKey());
////    String sql = sqlBuilder.toString();
//    String sql = sqlBuilder.toStringForIndexTable();

    String sql = EngineConstants.REWRITE_IDX_SELECT_TEMPLATE;
    sql = sql.replaceAll(EngineConstants.DUAL,index.getName());
    sql = sql.replaceAll(EngineConstants.REWRITE_PH_COLUMNS,index.getColumnsStr());
    String refColumn=index.getRefColumn();
    sql = sql.replaceAll(EngineConstants.REWRITE_PH_COLUMN_WHERE,refColumn);

    String originSql=context.getStatementContext().getOriginSql().toUpperCase();
    originSql=originSql.substring( originSql.indexOf( "WHERE" )+5 );
    int colIndex=originSql.indexOf( refColumn);
    if (colIndex>=0){
      String originSqlSuffix=originSql.substring( colIndex + refColumn.length() );
      String originSqlPrefix=originSql.substring( 0, colIndex);
      String tmpOriginSql=originSqlSuffix;
      String tmpStr=tmpOriginSql.substring(0,1);
      boolean isParaModule=false;
      String refColumnValue=null;
      while(true){
        if (" ".equals( tmpStr ) || "=".equals( tmpStr )){
          tmpOriginSql=tmpOriginSql.substring(1);
          if(tmpOriginSql.length()<1) break;
          tmpStr=tmpOriginSql.substring(0,1);
          continue;
        }
        if("?".equals( tmpStr )){
          isParaModule=true;
          break;
        }
        //既非" "  "=" 又非 "?",静态模式，固定值
        int spaceIndex= tmpOriginSql.indexOf( " " );
        if (spaceIndex>0){
          refColumnValue=tmpOriginSql.substring( 0,spaceIndex );
        }
        else{
          refColumnValue=tmpOriginSql;
        }
        break;
      }

      List<Object> parametersNew=new ArrayList<>(  );
      if(isParaModule){
        int qmIndex = originSqlPrefix.indexOf( "?" );
        int num=0;
        while(qmIndex>0) {
          num++;
          if (originSqlPrefix.length() <= (qmIndex + 1) ) break;
          originSqlPrefix = originSqlPrefix.substring( qmIndex + 1 );
          qmIndex = originSqlPrefix.indexOf( "?" );
        }
        parametersNew.add( parameters.get( num ) );
      }
      else{
        sql = sql.replaceAll("/?",refColumnValue);
      }
      IndexTableOps ops = new IndexTableOps();
      ops.setIdxSql(sql);
      ops.getParameters().addAll(parametersNew);
      ops.setCopy( false );
      return ops;
    }
    return null;
//    throw new GenericException( RouteErrCodes.ROUTE_432);
  }

  /*  private IndexTableOps assembleIndexOps(SqlBuilder sqlBuilder, List<Object> parameters,  Map<String, Index> indexTables){
    Map.Entry<String, Index> entry = null;
    Iterator<Entry<String, Index>> iterator = indexTables.entrySet().iterator();
    while(iterator.hasNext()){
      entry = iterator.next();
    }
    sqlBuilder.rewriteTable(entry.getKey());
//    String sql = sqlBuilder.toString();
    String sql = sqlBuilder.toStringForIndexTable();
    sql = sql.replaceAll(String.format(
            EngineConstants.REWRITE_PH_TBL_TEMPLATE,
            EngineConstants.REWRITE_PH_TBL_PREFIX, entry.getKey(), EngineConstants.REWRITE_PH_TBL_SUFFIX),
            entry.getValue().getName());
    IndexTableOps ops = new IndexTableOps();
    ops.getParameters().addAll(parameters);
    ops.setIdxSql(sql);
    return ops;
  }*/

}
